
package com.wd.base.thread;

import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

import com.wd.base.util.Logger;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * <带有生命周期的 Runnable>
 *
 * @author wangnaiwen
 * @version [V1.0.0.0, 2020/4/7]
 * @since V1.0.0.0
 */
public abstract class LifecycleRunnable implements Runnable {
    private static final String TAG = "LifecycleRunnable";

    private static final AtomicLong RUNNABLE_ID_COUNTER = new AtomicLong(0L);

    private static final ConcurrentHashMap<Long, LifecycleRunnable> RUNNABLE_CACHE = new ConcurrentHashMap();

    private final long runnableId;

    private final boolean isValid;

    public LifecycleRunnable(Lifecycle lifecycle) {
        if (lifecycle != null) {
            this.isValid = true;
            this.runnableId = RUNNABLE_ID_COUNTER.getAndIncrement();
            lifecycle.addObserver(new InnerLifecycleObserver(this.runnableId));
            RUNNABLE_CACHE.put(this.runnableId, this);
            Logger.i("LifecycleRunnable", "register runnable:" + this.runnableId);
        } else {
            this.isValid = false;
            this.runnableId = -1L;
            Logger.i("LifecycleRunnable", "lifecycle is null");
        }

    }

    /**
     * Runnable 转换成生命周期的 Runnable
     *
     * @param runnable 运行接口
     * @return Runnable
     */
    static Runnable transfer(Runnable runnable) {
        return (Runnable) (runnable instanceof LifecycleRunnable && ((LifecycleRunnable) runnable).isValid
            ? new LifecycleRunnableWrapper(((LifecycleRunnable) runnable).runnableId) : runnable);
    }

    /**
     * 生命周期观察者
     */
    private static class InnerLifecycleObserver implements LifecycleObserver {
        private final long runnableId;

        InnerLifecycleObserver(long id) {
            this.runnableId = id;
        }

        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        public void onDestroy() {
            Logger.i("LifecycleRunnable", "remove runnable id:" + this.runnableId);
            LifecycleRunnable.RUNNABLE_CACHE.remove(this.runnableId);
        }
    }

    private static class LifecycleRunnableWrapper implements Runnable {
        private final long runnableId;

        LifecycleRunnableWrapper(long id) {
            this.runnableId = id;
        }

        public void run() {
            Runnable runnable = (Runnable) LifecycleRunnable.RUNNABLE_CACHE.get(this.runnableId);
            if (runnable != null) {
                runnable.run();
            } else {
                Logger.i("LifecycleRunnable", "runnable is released");
            }

        }
    }
}
